package com.lidong.zc.databasemodel.init.core;


import com.alibaba.druid.pool.DruidPooledConnection;
import com.lidong.zc.databasemodel.constants.enumconst.SqlTypeEnum;
import com.lidong.zc.databasemodel.entity.BCreateTableDO;
import com.lidong.zc.databasemodel.entity.database.DataBaseTable;
import com.lidong.zc.databasemodel.init.intf.CreateTableHandle;
import com.lidong.zc.databasemodel.mapper.InitDataBaseMapper;
import com.lidong.zc.databasemodel.utils.InitDataBaseUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.util.ObjectUtils;

import java.sql.SQLException;
import java.util.*;

/**
 * @author LiDong
 * @version 1.0.0
 * @createTime 9/17/2022 9:53 PM
 */
public class CreateTableManage {

    private static final Logger logger = LoggerFactory.getLogger(CreateTableManage.class);

    private InitDataBaseContext initDataBaseContext;

    protected JdbcTemplate jdbcTemplate;

    public CreateTableManage() {
    }

    public CreateTableManage(InitDataBaseContext initDataBaseContext) {
        this.initDataBaseContext = initDataBaseContext;
        jdbcTemplate = initDataBaseContext.getJdbcTemplate();
    }

    /**
     * 开始建表
     */
    public void start() throws SQLException {
        // 获取数据库中现有的表查询数据库的元数据
        List<DataBaseTable> oldTableList = this.getAllTableInSchema();
        // 查询建表记录获取已经记录的版本号
        // List<BCreateTableDO> bCreateTableDOList = getBCreateTableDOList(oldTableList);
        // 获取所有需要创建或者更新的表
        List<DataBaseTable> dataBaseTableList = initDataBaseContext.getDataBaseTableList();
        // 获取要新创建的表
        List<DataBaseTable> needCreateTableList = this.getNeedCreateTableList(oldTableList, dataBaseTableList);
        // 获取需要更新的表
        List<DataBaseTable> needUpdateTableList = this.getNeedUpdateTableList(oldTableList, dataBaseTableList);
        // 获取 CreateTableManage 实例
        CreateTableHandle createTableHandleInstance = DataBaseFactory.getCreateTableManageInstance(initDataBaseContext);
        // 建表
        createTableHandleInstance.startCreateTable(needCreateTableList);
        // 更新表
        createTableHandleInstance.startUpdateTable(needUpdateTableList, oldTableList);
    }

    /**
     * 获取需要更新的表
     *
     * @param originalDataBaseTableList 数据库元数据记录
     * @param dataBaseTableList         扫描的需要创建或者更新的表
     * @return List
     */
    private List<DataBaseTable> getNeedUpdateTableList(List<DataBaseTable> originalDataBaseTableList, List<DataBaseTable> dataBaseTableList) {
        List<DataBaseTable> tableList = new ArrayList<>();
        for (DataBaseTable dataBaseTable : dataBaseTableList) {
            String tempTableName = dataBaseTable.getTableName().toLowerCase(Locale.ROOT);
            boolean flag = false;
            for (DataBaseTable originalDataBaseTable : originalDataBaseTableList) {
                String tableName = originalDataBaseTable.getTableName().toLowerCase(Locale.ROOT);
                if (tempTableName.equalsIgnoreCase(tableName)) {
                    flag = true;
                    break;
                }
            }
            // 找到已经建过的表
            if (flag) {
                tableList.add(dataBaseTable);
            }
        }
        return tableList;
    }

    /**
     * 获取要新创建的表
     *
     * @param originalDataBaseTableList 数据库元数据
     * @param dataBaseTableList         扫描的需要创建或者更新的表
     * @return List
     */
    private List<DataBaseTable> getNeedCreateTableList(List<DataBaseTable> originalDataBaseTableList, List<DataBaseTable> dataBaseTableList) {
        List<DataBaseTable> tableList = new ArrayList<>();
        boolean flag = false;
        for (DataBaseTable dataBaseTable : dataBaseTableList) {
            String tempTableName = dataBaseTable.getTableName().toLowerCase(Locale.ROOT);
            for (DataBaseTable originalDataBaseTable : originalDataBaseTableList) {
                String tableName = originalDataBaseTable.getTableName().toLowerCase(Locale.ROOT);
                if (tempTableName.equalsIgnoreCase(tableName)) {
                    flag = true;
                    break;
                }
            }
            if (!flag) {
                tableList.add(dataBaseTable);
            }
        }
        return tableList;
    }

    /**
     * 获取之前的数据库建表记录
     *
     * @param oldTableList
     * @return List
     * @throws SQLException SQLException
     */
    private List<BCreateTableDO> getBCreateTableDOList(List<DataBaseTable> oldTableList) throws SQLException {
        List<BCreateTableDO> bCreateTableDOList = new ArrayList<>();
        if (ObjectUtils.isEmpty(oldTableList)) {
            DruidPooledConnection druidPooledConnection = initDataBaseContext.getDruidPooledConnection();
            String schema = druidPooledConnection.getSchema();
            String catalog = druidPooledConnection.getCatalog();
            SqlTypeEnum sqlType = initDataBaseContext.getSqlType();
            InitDataBaseMapper initDataBaseMapper = InitDataBaseUtils.getInitDataBaseMapper();
            BCreateTableDO bCreateTableDO = new BCreateTableDO();
            bCreateTableDO.setDbType(sqlType.name());
            bCreateTableDO.setSchema(catalog);
            bCreateTableDO.setModel(null);
            return Optional.ofNullable(initDataBaseMapper.listBCreateTableDOList(bCreateTableDO)).orElse(Collections.emptyList());
        }
        BCreateTableDO bCreateTableDO;
        for (DataBaseTable dataBaseTable : oldTableList) {
            bCreateTableDO = new BCreateTableDO();
            // bCreateTableDO.setSchema();
            bCreateTableDO.setTableName(dataBaseTable.getTableName());
            bCreateTableDOList.add(bCreateTableDO);
        }
        return bCreateTableDOList;
    }

    /**
     * 获取数据库中现有的表
     *
     * @return List
     */
    private List<DataBaseTable> getAllTableInSchema() throws SQLException {
        AbstractCreateTableManage abstractCreateTableManage = DataBaseFactory.getAbstractCreateTableManage(initDataBaseContext);
        List<DataBaseTable> dataBaseTableList = abstractCreateTableManage.getDataBaseTableList();
        abstractCreateTableManage.getColumnList(dataBaseTableList);
        abstractCreateTableManage.getIndexList(dataBaseTableList);
        return dataBaseTableList;
    }

    public InitDataBaseContext getInitDataBaseContext() {
        return initDataBaseContext;
    }

    public void setInitDataBaseContext(InitDataBaseContext initDataBaseContext) {
        this.initDataBaseContext = initDataBaseContext;
    }

    /**
     * 获取 JdbcTemplate
     *
     * @return JdbcTemplate
     */
    public JdbcTemplate getJdbcTemplate() {
        return initDataBaseContext.getJdbcTemplate();
    }

}
